/**
 * 
 */
package parallel.project.framework;

import java.awt.Point;
import java.awt.Rectangle;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Random;

import parallel.project.graph.Path;


/**
 * @author aclayton
 *
 */
public class MazeGenerator {
	private int width, height;
	private Mazemap map;
	
	public MazeGenerator(int width, int height){
		this.width = width;
		this.height = height;
		map = new Mazemap(width, height);
	}
	
	public HashSet<Point> getNeighboringCells(Rectangle mazeBox, Point pt){
		HashSet<Point> neighbors = new HashSet<Point>();
		
		Point temp = new Point(pt.x+1,pt.y);
		if(mazeBox.contains(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.x-1,pt.y);
		if(mazeBox.contains(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.x,pt.y+1);
		if(mazeBox.contains(temp))
			neighbors.add(temp);
		
		temp = new Point(pt.x,pt.y-1);
		if(mazeBox.contains(temp))
			neighbors.add(temp);
		
		return neighbors;
		
	}
	
	public void runPrimsAlgorithm(){
		for(int a = 0; a < width; a++){
			for(int b = 0; b < height; b++)
				map.setCell(a, b, 1);
		}
		
		map.setCell(1, 1, 0);
		HashSet<Point> wallList = new HashSet<Point>();
		wallList.addAll(getNeighboringCells(map.getBounds(),new Point(1,1)));
		
		while(!wallList.isEmpty()){
			
			Point currentWall = wallList.iterator().next();
			
			
			HashSet<Point> neighboringPts = getNeighboringCells(map.getBounds(),currentWall);
			Point neighboringPassage = new Point();
			for(Point temp : neighboringPts){
				if(map.getCell(temp.x,temp.y) == 0){
					neighboringPassage = temp;
					break;
				}
			}
			
			int oppositeX = (currentWall.x-neighboringPassage.x)+currentWall.x;
			int oppositeY = (currentWall.y-neighboringPassage.y)+currentWall.y;
			Point opposite = new Point(oppositeX, oppositeY);
			
			if(!map.getBounds().contains(opposite)){
				wallList.remove(currentWall);
				continue;
			}
			
			if(map.getCell(oppositeX, oppositeY) == 0){
				wallList.remove(currentWall);
			} else {
				map.setCell(currentWall.x, currentWall.y, 0);
				map.setCell(oppositeX, oppositeY, 0);
				HashSet<Point> oppositeNieghbors = getNeighboringCells(map.getBounds(),opposite);
				for(Point oppositeNieghbor : oppositeNieghbors){
					if(map.getCell(oppositeNieghbor.x, oppositeNieghbor.y) == 1)
						wallList.add(oppositeNieghbor);
				}
				wallList.remove(currentWall);
			}
		}
		this.assignStartEndPoints();
		System.out.println(this.map.getStart() + " " + this.map.getEnd());
		this.map.printMazemap();
	}
	
	public Mazemap getMaze(){
		return map;
	}
	
	public void assignStartEndPoints()
	{
		Random ran = new Random();
		int x,y;
		// pick a random point in the first 2 columns for the start 
		// and a random point in the last 2 columns for the end
		Point start = null;
		Point end = null;
		// keep picking random points in the first 2 columns until get
		// one that is a passage
		while (start == null)
		{
			x = ran.nextInt(2);
			y = ran.nextInt(this.map.getHeight());
			if (this.map.isPassage(x,y) && y != 0 && 
				y != (this.map.getHeight() - 1))
				start = new Point(x,y);
		}
		// keep picking random points in the last 2 columns until get
		// on that is a passage
		while (end == null)
		{
			x = ran.nextInt(2) + this.map.getWidth() - 2;
			y = ran.nextInt(this.map.getHeight());
			if (this.map.isPassage(x,y) && y != 0 && 
				y != (this.map.getHeight() - 1))
				end = new Point(x,y);
		}
		// set the found start and end points
		this.map.setStart(start);
		this.map.setEnd(end);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if(args.length != 3){
			System.out.println("Usage");
			System.out.println("MazeGenerator mapwidth mapheight savelocation");
			System.exit(0);
		}
		
		int width = Integer.parseInt(args[0]);
		int height = Integer.parseInt(args[1]);
		String saveLocation = args[2];
		
		System.out.println(width);
		System.out.println(height);
		System.out.println(saveLocation);

		MazeGenerator mgen = new MazeGenerator(width, height);
		mgen.runPrimsAlgorithm();
		Mazemap map = mgen.getMaze();
		
		FileOutputStream fos = null;
		ObjectOutputStream out = null;
		try{
			fos = new FileOutputStream(saveLocation);
			out = new ObjectOutputStream(fos);
			out.writeObject(map);
			out.close();
			
		} catch (Exception ex){
			ex.printStackTrace();
		}
		
		Mazemap map2 = null;
		FileInputStream fis;
		ObjectInputStream in;
		
		System.out.println(args[1]);
		try{
			fis = new FileInputStream(saveLocation);
			in = new ObjectInputStream(fis);
			map2 = (Mazemap)in.readObject();
			in.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

}
